﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Runtime.Serialization;
using log4net;
using System.Reflection;

[XmlRoot("Dictionary")]
public class SerializableDictionary<TKey, TValue>
    : Dictionary<TKey, TValue>, IXmlSerializable
{
    private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    #region IXmlSerializable Members
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public SerializableDictionary()

        : base()
    {

    }

    public SerializableDictionary(IDictionary<TKey, TValue> dictionary)

        : base(dictionary)
    {

    }

    public SerializableDictionary(IEqualityComparer<TKey> comparer)

        : base(comparer)
    {

    }

    public SerializableDictionary(int capacity)

        : base(capacity)
    {

    }

    public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)

        : base(dictionary, comparer)
    {

    }

    public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)

        : base(capacity, comparer)
    {

    }

    protected SerializableDictionary(SerializationInfo info, StreamingContext context)

        : base(info, context)
    {

    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        try
        {
            XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
            XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

            bool wasEmpty = reader.IsEmptyElement;
            reader.Read();

            if (wasEmpty)
                return;

            reader.ReadStartElement("dictionary");
            while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
            {
                reader.ReadStartElement("item");

                reader.ReadStartElement("key");
                TKey key = (TKey)keySerializer.Deserialize(reader);
                reader.ReadEndElement();

                Debug.WriteLine("Reading key: " + key);

                reader.ReadStartElement("value");
                TValue value = (TValue)valueSerializer.Deserialize(reader);
                reader.ReadEndElement();

                this.Add(key, value);

                reader.ReadEndElement();
                reader.MoveToContent();
            }
            reader.ReadEndElement();
            //reader.Close();
        }
        catch(Exception ex)
        {
            log.Error("", ex);            
        }
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        writer.WriteStartElement("dictionary");
        foreach (TKey key in this.Keys)
        {
            writer.WriteStartElement("item");
  //          writer.WriteRaw("\n\t");

            writer.WriteStartElement("key");
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();

//            writer.WriteRaw("\n\t");
            writer.WriteStartElement("value");
            TValue value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
        writer.WriteEndElement();
        writer.Flush();
        writer.Close();
    }
    #endregion

    public static SerializableDictionary<TKey, TValue> Deserialize(string FileName)
    {
        SerializableDictionary<TKey, TValue> q = new SerializableDictionary<TKey, TValue>();

        try
        {
            if ((FileName != null) && (FileName != "") && (FileName != string.Empty))
            {
                if (File.Exists(FileName))
                {
                    using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        using (StreamReader sr = new StreamReader(fs))
                        {
                            using (XmlReader r = new XmlTextReader(sr))
                            {
                                q.ReadXml(r);
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            log.Error("", ex);                        
        }

        return q;
    }
    public static int WriteAttempts = 0;
    public static void Serialize(string FileName, SerializableDictionary<TKey, TValue> s)
    {
        try
        {
            using (XmlWriter w = new XmlTextWriter(FileName, Encoding.Unicode))
            {
                s.WriteXml(w);
                WriteAttempts = 0;
            }
        }
        catch (IOException ex)
        {
            log.Error("", ex);
        }
        catch (Exception ex)
        {
            log.Error("", ex);            
        }

    }
}